import 'dart:ffi';

import 'package:drift/drift.dart';
import 'package:flutter_crud_test_amir_rabbani/core/params/create_customer_params.dart';
import 'package:flutter_crud_test_amir_rabbani/core/params/edit_customer_params.dart';
import 'package:flutter_crud_test_amir_rabbani/core/resource/data_state.dart';
import 'package:flutter_crud_test_amir_rabbani/core/resource/use_case.dart';
import 'package:flutter_crud_test_amir_rabbani/core/utils/regex_helper.dart';
import 'package:flutter_crud_test_amir_rabbani/data/datasources/customer_datasource.dart';
import 'package:flutter_crud_test_amir_rabbani/data/local/dao/customer_dao.dart';
import 'package:flutter_crud_test_amir_rabbani/data/local/my_database.dart';
import 'package:flutter_crud_test_amir_rabbani/data/repositories/customer_repository.dart';
import 'package:flutter_libphonenumber/flutter_libphonenumber.dart';

class CustomerRepositoryImpl extends CustomerRepository {
  CustomerDataSource _datasource;

  CustomerRepositoryImpl(this._datasource);

  @override
  Future<DataState<NoResponse>> create(CreateCustomerParams params) async {
    bool isValidPhone;
    String phone = '';
    try {
      final parsed = await parse(params.phoneNumber);
      phone = parsed['international'];
      isValidPhone = true;
    } catch (e) {
      isValidPhone = false;
    }
    if (!isValidPhone) return DataFailed('Invalid phone number format.');

    bool isValidFirstName = firstNameRegex.hasMatch(params.firstName);
    if (!isValidFirstName) {
      return DataFailed('First name must only contain letters.');
    }

    bool isValidLastName = lastNameRegex.hasMatch(params.lastName);
    if (!isValidLastName) {
      return DataFailed('Last name must only contain letters.');
    }

    bool isValidEmail = emailRegex.hasMatch(params.email);
    if (!isValidEmail) return DataFailed('Invalid email address format.');

    bool isValidBank =
        bankAccountNumberRegex.hasMatch(params.bankAccountNumber);
    if (!isValidBank) {
      return DataFailed('Bank account number must contain 10 to 20 digits.');
    }

    bool isValidBirthday = params.dateOfBirth != null &&
        params.dateOfBirth!.isBefore(DateTime.now());
    if (!isValidBirthday) {
      return DataFailed('Invalid date of birth. Date must be in the past.');
    }

    _datasource.create(CustomerDaoCompanion(
        firstName: Value(params.firstName),
        lastName: Value(params.lastName),
        dateOfBirth: Value(params.dateOfBirth!),
        phoneNumber: Value(phone),
        email: Value(params.email),
        bankAccountNumber: Value(params.bankAccountNumber)));
    return DataSuccess(NoResponse());
  }

  @override
  Future<DataState<NoResponse>> delete(int params) async {
    _datasource.delete(params);
    return DataSuccess(NoResponse());
  }

  @override
  Future<DataState<NoResponse>> edit(EditCustomerParams params) async {
    bool isValidPhone;
    String phone = '';
    try {
      final parsed = await parse(params.phoneNumber);
      phone = parsed['international'];
      isValidPhone = true;
    } catch (e) {
      isValidPhone = false;
    }
    if (!isValidPhone) return DataFailed('Invalid phone number format.');

    bool isValidFirstName = firstNameRegex.hasMatch(params.firstName);
    if (!isValidFirstName) {
      return DataFailed('First name must only contain letters.');
    }

    bool isValidLastName = lastNameRegex.hasMatch(params.lastName);
    if (!isValidLastName) {
      return DataFailed('Last name must only contain letters.');
    }

    bool isValidEmail = emailRegex.hasMatch(params.email);
    if (!isValidEmail) return DataFailed('Invalid email address format.');

    bool isValidBank =
        bankAccountNumberRegex.hasMatch(params.bankAccountNumber);
    if (!isValidBank) {
      return DataFailed('Bank account number must contain 10 to 20 digits.');
    }

    bool isValidBirthday = params.dateOfBirth != null &&
        params.dateOfBirth!.isBefore(DateTime.now());
    if (!isValidBirthday) {
      return DataFailed('Invalid date of birth. Date must be in the past.');
    }

    _datasource.edit(
        params.id,
        CustomerDaoCompanion(
            firstName: Value(params.firstName),
            lastName: Value(params.lastName),
            dateOfBirth: Value(params.dateOfBirth!),
            phoneNumber: Value(phone),
            email: Value(params.email),
            bankAccountNumber: Value(params.bankAccountNumber)));
    return DataSuccess(NoResponse());
  }

  @override
  Stream read() {
    return _datasource.read();
  }

  @override
  Future<DataState<CustomerDaoData>> readById(int id) async {
    List<CustomerDaoData> data = await _datasource.readById(id);
    return DataSuccess(data.first);
  }
}
